/* Debug codes for MIDPath. See MIDPath-patch. */

#include <jni.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdint.h>

#include <sys/ioctl.h>
#include <sys/mman.h>
#include <termios.h>
#include <sys/vt.h>
#include <sys/time.h>
#include <sys/types.h>

#include <linux/fb.h>
#include <linux/kd.h>
#include <linux/keyboard.h>
#include <linux/input.h>

#define NR_MAPS 16

/* Keyboard variables */
static int keyboard_fd;
static int keychar_map[NR_MAPS][NR_KEYS];
static int keycode_map[NR_MAPS][NR_KEYS];
static int map = K_NORMTAB;

enum { 	VK_ENTER = '\n', VK_BACK_SPACE = '\b', VK_TAB = '\t', VK_CANCEL = 3, VK_CLEAR = 12, VK_SHIFT = 16,
		VK_CONTROL = 17, VK_ALT = 18, VK_PAUSE = 19, VK_CAPS_LOCK = 20, VK_ESCAPE = 27, VK_SPACE = ' ',
		VK_PAGE_UP = 33, VK_PAGE_DOWN = 34, VK_END = 35, VK_HOME = 36, VK_LEFT = 37, VK_UP = 38, VK_RIGHT = 39,
		VK_DOWN = 40, VK_COMMA = ',', VK_MINUS = '-', VK_PERIOD = '.', VK_SLASH = '/', VK_0 = '0', VK_1 = '1',
		VK_2 = '2', VK_3 = '3', VK_4 = '4', VK_5 = '5', VK_6 = '6', VK_7 = '7', VK_8 = '8', VK_9 = '9',
		VK_SEMICOLON = ',', VK_EQUALS = '=', VK_A = 'A', VK_B = 'B', VK_C = 'C', VK_D = 'D', VK_E = 'E',
		VK_F = 'F', VK_G = 'G', VK_H = 'H', VK_I = 'I', VK_J = 'J', VK_K = 'K', VK_L = 'L', VK_M = 'M', VK_N = 'N',
		VK_O = 'O', VK_P = 'P', VK_Q = 'Q', VK_R = 'R', VK_S = 'S', VK_T = 'T', VK_U = 'U', VK_V = 'V', VK_W = 'W',
		VK_X = 'X', VK_Y = 'Y', VK_Z = 'Z', VK_OPEN_BRACKET = '[', VK_BACK_SLASH = '\\', VK_CLOSE_BRACKET = ']',
		VK_NUMPAD0 = 96, VK_NUMPAD1 = 97, VK_NUMPAD2 = 98, VK_NUMPAD3 = 99, VK_NUMPAD4 = 100, VK_NUMPAD5 = 101,
		VK_NUMPAD6 = 102, VK_NUMPAD7 = 103, VK_NUMPAD8 = 104, VK_NUMPAD9 = 105, VK_MULTIPLY = 106, VK_ADD = 107,
		VK_SEPARATER = 108, VK_SEPARATOR = 108, VK_SUBTRACT = 109, VK_DECIMAL = 110, VK_DIVIDE = 111,
		VK_DELETE = 127, VK_NUM_LOCK = 144, VK_SCROLL_LOCK = 145, VK_F1 = 112, VK_F2 = 113, VK_F3 = 114,
		VK_F4 = 115, VK_F5 = 116, VK_F6 = 117, VK_F7 = 118, VK_F8 = 119, VK_F9 = 120, VK_F10 = 121, VK_F11 = 122,
		VK_F12 = 123, VK_F13 = 61440, VK_F14 = 61441, VK_F15 = 61442, VK_F16 = 61443, VK_F17 = 61444,
		VK_F18 = 61445, VK_F19 = 61446, VK_F20 = 61447, VK_F21 = 61448, VK_F22 = 61449, VK_F23 = 61450,
		VK_F24 = 61451, VK_PRINTSCREEN = 154, VK_INSERT = 155, VK_HELP = 156, VK_META = 157, VK_BACK_QUOTE = 192,
		VK_QUOTE = 222, VK_KP_UP = 224, VK_KP_DOWN = 225, VK_KP_LEFT = 226, VK_KP_RIGHT = 227, VK_DEAD_GRAVE = 128,
		VK_DEAD_ACUTE = 129, VK_DEAD_CIRCUMFLEX = 130, VK_DEAD_TILDE = 131, VK_DEAD_MACRON = 132,
		VK_DEAD_BREVE = 133, VK_DEAD_ABOVEDOT = 134, VK_DEAD_DIAERESIS = 135, VK_DEAD_ABOVERING = 136,
		VK_DEAD_DOUBLEACUTE = 137, VK_DEAD_CARON = 138, VK_DEAD_CEDILLA = 139, VK_DEAD_OGONEK = 140,
		VK_DEAD_IOTA = 141, VK_DEAD_VOICED_SOUND = 142, VK_DEAD_SEMIVOICED_SOUND = 143, VK_AMPERSAND = 150,
		VK_ASTERISK = 151, VK_QUOTEDBL = 152, VK_LESS = 153, VK_GREATER = 160, VK_BRACELEFT = 161,
		VK_BRACERIGHT = 162, VK_AT = 512, VK_COLON = 513, VK_CIRCUMFLEX = 514, VK_DOLLAR = 515, VK_EURO_SIGN = 516,
		VK_EXCLAMATION_MARK = 517, VK_INVERTED_EXCLAMATION_MARK = 518, VK_LEFT_PARENTHESIS = 519,
		VK_NUMBER_SIGN = 520, VK_PLUS = 521, VK_RIGHT_PARENTHESIS = 522, VK_UNDERSCORE = 523, VK_FINAL = 24,
		VK_CONVERT = 28, VK_NONCONVERT = 29, VK_ACCEPT = 30, VK_MODECHANGE = 31, VK_KANA = 21, VK_KANJI = 25,
		VK_ALPHANUMERIC = 240, VK_KATAKANA = 241, VK_HIRAGANA = 242, VK_FULL_WIDTH = 243, VK_HALF_WIDTH = 244,
		VK_ROMAN_CHARACTERS = 245, VK_ALL_CANDIDATES = 256, VK_PREVIOUS_CANDIDATE = 257, VK_CODE_INPUT = 258,
		VK_JAPANESE_KATAKANA = 259, VK_JAPANESE_HIRAGANA = 260, VK_JAPANESE_ROMAN = 261, VK_KANA_LOCK = 262,
		VK_INPUT_METHOD_ON_OFF = 263, VK_CUT = 65489, VK_COPY = 65485, VK_PASTE = 65487, VK_UNDO = 65483,
		VK_AGAIN = 65481, VK_FIND = 65488, VK_PROPS = 65482, VK_STOP = 65480, VK_COMPOSE = 65312,
		VK_ALT_GRAPH = 65406, VK_BEGIN = 65368, VK_CONTEXT_MENU = 525, VK_WINDOWS = 524, VK_UNDEFINED = 0 };

static int CHAR_UNDEFINED = 65535; // '\uffff'

static void init_keymap(int kb_fd) {
	struct kbentry entry;
    int keycode, map;

	for (map = 0; map < NR_MAPS; map++) {
    	for (keycode = 0; keycode < NR_KEYS; keycode++) {
            
            keychar_map[map][keycode] = CHAR_UNDEFINED;
        	keycode_map[map][keycode] = VK_UNDEFINED;
        	
        	/* KVAL(entry.kb_value) will be the
           	8-bit representation of the character the kernel
           	has mapped to this keycode. */
        	entry.kb_table = map;
        	entry.kb_index = keycode;
			
			/* Map visible chars to standard ASCII chars and modifier keys to some useless ASCII chars */
        	int kval = KVAL(entry.kb_value);
        	switch (KTYP(entry.kb_value)) {
			case KT_SHIFT:
				switch (entry.kb_value) {
				case K_ALTGR:
				case K_ALT:
		    		keycode_map[map][keycode] = VK_ALT;
		    		break;
				case K_CTRL:
				case K_CTRLL:
				case K_CTRLR:
		    		keycode_map[map][keycode] = VK_CONTROL;
		    		break;
				case K_SHIFT:
				case K_SHIFTL:
				case K_SHIFTR:
					keycode_map[map][keycode] = VK_SHIFT;
		    		break;
				default:
		    		break;
				}
				break;
			case KT_FN:
				if (kval < 12)
		    		keycode_map[map][keycode] = VK_F1 + kval;
				else switch (entry.kb_value) {
				case K_FIND:
		    		keycode_map[map][keycode] = VK_FIND;
		    		break;
				case K_INSERT:
		    		keycode_map[map][keycode] = VK_INSERT;
		    		break;
				case K_REMOVE:
		    		keycode_map[map][keycode] = VK_DELETE;
		    		break;
				case K_SELECT:
		    		keycode_map[map][keycode] = VK_END;
		    		break;
				case K_PGUP:
		    		keycode_map[map][keycode] = VK_PAGE_UP;
		    		break;
				case K_PGDN:
		    		keycode_map[map][keycode] = VK_PAGE_DOWN;
		    		break;
		    	case K_UNDO:
		    		keycode_map[map][keycode] = VK_UNDO;
				default:
		    		break;
				}
				break;
			case KT_CUR:
				switch (entry.kb_value) {
				case K_DOWN:
		    		keycode_map[map][keycode] = VK_DOWN;
		    		break;
				case K_LEFT:
		    		keycode_map[map][keycode] = VK_LEFT;
		    		break;
				case K_RIGHT:
		    		keycode_map[map][keycode] = VK_RIGHT;
		    		break;
				case K_UP:
		    		keycode_map[map][keycode] = VK_UP;
		    		break;
				}
				break;
			 case KT_SPEC:
				switch (entry.kb_value) {
				case K_ENTER:
		    		keycode_map[map][keycode] = VK_ENTER;
		    		break;   
				case K_CAPS:
					keycode_map[map][keycode] = VK_CAPS_LOCK;
					break;          
				case K_NUM:
					keycode_map[map][keycode] = VK_NUM_LOCK;
					break;          
				}
				break;
			case KT_PAD:
				switch (entry.kb_value) {
				case K_P0:
					keycode_map[map][keycode] = VK_NUMPAD0;
					keychar_map[map][keycode] = kval;
					break;
				case K_P1:
					keycode_map[map][keycode] = VK_NUMPAD1;
					keychar_map[map][keycode] = kval;
					break;
				case K_P2:
					keycode_map[map][keycode] = VK_NUMPAD2;
					keychar_map[map][keycode] = kval;
					break;
				case K_P3:
					keycode_map[map][keycode] = VK_NUMPAD3;
					keychar_map[map][keycode] = kval;
					break;
				case K_P4:
					keycode_map[map][keycode] = VK_NUMPAD4;
					keychar_map[map][keycode] = kval;
					break;
				case K_P5:
					keycode_map[map][keycode] = VK_NUMPAD5;
					keychar_map[map][keycode] = kval;
					break;
				case K_P6:
					keycode_map[map][keycode] = VK_NUMPAD6;
					keychar_map[map][keycode] = kval;
					break;
				case K_P7:
					keycode_map[map][keycode] = VK_NUMPAD7;
					keychar_map[map][keycode] = kval;
					break;
				case K_P8:
					keycode_map[map][keycode] = VK_NUMPAD8;
					keychar_map[map][keycode] = kval;
					break;
				case K_P9:
					keycode_map[map][keycode] = VK_NUMPAD9;
					keychar_map[map][keycode] = kval;
					break;
				case K_PENTER:
		    		keycode_map[map][keycode] = VK_ENTER;
		    		break;
				}
		    	break;
		    case KT_ASCII:
		    	if (((kval >= '0') && (kval <= '9')) || ((kval >= 'a') && (kval <= 'z')) || ((kval >= 'A') && (kval <= 'Z'))) {
		    		keychar_map[map][keycode] = kval;
		    		keycode_map[map][keycode] = kval;
		    		break;
		    	} else if (kval == 13) {
        			keychar_map[map][keycode] = 13;
        			keycode_map[map][keycode] = VK_ENTER;
		    	} else {
		    		keychar_map[map][keycode] = kval;
					keycode_map[map][keycode] = VK_UNDEFINED;
		    	}
		    	break;
			default:
				keychar_map[map][keycode] = kval;
				keycode_map[map][keycode] = VK_UNDEFINED;
				break;
        	}
         
        	//printf("keycode_map[%i][%i]=%i\n", map, keycode, keycode_map[map][keycode]);
        	//printf("keychar_map[%i][%i]=%c\n", map, keycode, keychar_map[map][keycode]);
    
    	}
	}
        
}

static void closeKeyboard() {
    /* Only bother closing the keyboard fd if it's not stdin, stdout, or stderr. */
    if (keyboard_fd > 3)
        close(keyboard_fd);
}

static int evcodetovk[] = {
	/* KEY_RESERVED */ VK_UNDEFINED,
	/* KEY_ESC */ VK_ESCAPE,
	/* KEY_1 */ VK_1,
	/* KEY_2 */ VK_2,
	/* KEY_3 */ VK_3,
	/* KEY_4 */ VK_4,
	/* KEY_5 */ VK_5,
	/* KEY_6 */ VK_6,
	/* KEY_7 */ VK_7,
	/* KEY_8 */ VK_8,
	/* KEY_9 */ VK_9,
	/* KEY_0 */ VK_0,
	/* KEY_MINUS */ VK_MINUS,
	/* KEY_EQUAL */ VK_EQUALS,
	/* KEY_BACKSPACE */ VK_BACK_SPACE,
	/* KEY_TAB */ VK_TAB,
	/* KEY_Q */ VK_Q,
	/* KEY_W */ VK_W,
	/* KEY_E */ VK_E,
	/* KEY_R */ VK_R,
	/* KEY_T */ VK_T,
	/* KEY_Y */ VK_Y,
	/* KEY_U */ VK_U,
	/* KEY_I */ VK_I,
	/* KEY_O */ VK_O,
	/* KEY_P */ VK_P,
	/* KEY_LEFTBRACE */ VK_OPEN_BRACKET,
	/* KEY_RIGHTBRACE */ VK_CLOSE_BRACKET,
	/* KEY_ENTER */ VK_ENTER,
	/* KEY_LEFTCTRL */ VK_CONTROL,
	/* KEY_A */ VK_A,
	/* KEY_S */ VK_S,
	/* KEY_D */ VK_D,
	/* KEY_F */ VK_F,
	/* KEY_G */ VK_G,
	/* KEY_H */ VK_H,
	/* KEY_J */ VK_J,
	/* KEY_K */ VK_K,
	/* KEY_L */ VK_L,
	/* KEY_SEMICOLON */ VK_SEMICOLON,
	/* KEY_APOSTROPHE */ VK_UNDEFINED,
	/* KEY_GRAVE */ VK_UNDEFINED,
	/* KEY_LEFTSHIFT */ VK_SHIFT,
	/* KEY_BACKSLASH */ VK_BACK_SLASH,
	/* KEY_Z */ VK_Z,
	/* KEY_X */ VK_X,
	/* KEY_C */ VK_C,
	/* KEY_V */ VK_V,
	/* KEY_B */ VK_B,
	/* KEY_N */ VK_N,
	/* KEY_M */ VK_M,
	/* KEY_COMMA */ VK_COMMA,
	/* KEY_DOT */ VK_PERIOD,
	/* KEY_SLASH */ VK_SLASH,
	/* KEY_RIGHTSHIFT */ VK_SHIFT,
	/* KEY_KPASTERISK */ VK_ASTERISK,
	/* KEY_LEFTALT */ VK_ALT,
	/* KEY_SPACE */ VK_SPACE,
	/* KEY_CAPSLOCK */ VK_CAPS_LOCK,
	/* KEY_F1 */ VK_F1,
	/* KEY_F2 */ VK_F2,
	/* KEY_F3 */ VK_F3,
	/* KEY_F4 */ VK_F4,
	/* KEY_F5 */ VK_F5,
	/* KEY_F6 */ VK_F6,
	/* KEY_F7 */ VK_F7,
	/* KEY_F8 */ VK_F8,
	/* KEY_F9 */ VK_F9,
	/* KEY_F10 */ VK_F10,
	/* KEY_NUMLOCK */ VK_NUM_LOCK,
	/* KEY_SCROLLLOCK */ VK_SCROLL_LOCK,
	/* KEY_KP7 */ VK_NUMPAD7,
	/* KEY_KP8 */ VK_NUMPAD8,
	/* KEY_KP9 */ VK_NUMPAD9,
	/* KEY_KPMINUS */ VK_MINUS,
	/* KEY_KP4 */ VK_NUMPAD4,
	/* KEY_KP5 */ VK_NUMPAD5,
	/* KEY_KP6 */ VK_NUMPAD6,
	/* KEY_KPPLUS */ VK_PLUS,
	/* KEY_KP1 */ VK_NUMPAD1,
	/* KEY_KP2 */ VK_NUMPAD2,
	/* KEY_KP3 */ VK_NUMPAD3,
	/* KEY_KP0 */ VK_NUMPAD0,
	/* KEY_KPDOT */ VK_PERIOD,
	/* KEY_NUMBER84 */ VK_UNDEFINED,
	/* KEY_ZENKAKUHANKAKU */ VK_UNDEFINED,
	/* KEY_102ND */ VK_UNDEFINED,
	/* KEY_F11 */ VK_F11,
	/* KEY_F12 */ VK_F12,
	/* KEY_RO */ VK_UNDEFINED,
	/* KEY_KATAKANA */ VK_KATAKANA,
	/* KEY_HIRAGANA */ VK_HIRAGANA,
	/* KEY_HENKAN */ VK_UNDEFINED,
	/* KEY_KATAKANAHIRAGANA */ VK_UNDEFINED,
	/* KEY_MUHENKAN */ VK_UNDEFINED,
	/* KEY_KPJPCOMMA */ VK_UNDEFINED,
	/* KEY_KPENTER */ VK_ENTER,
	/* KEY_RIGHTCTRL */ VK_CONTROL,
	/* KEY_KPSLASH */ VK_SLASH,
	/* KEY_SYSRQ */ VK_UNDEFINED,
	/* KEY_RIGHTALT */ VK_ALT,
	/* KEY_LINEFEED */ VK_ENTER,
	/* KEY_HOME */ VK_HOME,
	/* KEY_UP */ VK_UP,
	/* KEY_PAGEUP */ VK_PAGE_UP,
	/* KEY_LEFT */ VK_LEFT,
	/* KEY_RIGHT */ VK_RIGHT,
	/* KEY_END */ VK_END,
	/* KEY_DOWN */ VK_DOWN,
	/* KEY_PAGEDOWN */ VK_PAGE_DOWN,
	/* KEY_INSERT */ VK_INSERT,
	/* KEY_DELETE */ VK_DELETE,
};

static void handleKeyEvent() {
	/* Reference: http://www.frogmouth.net/hid-doco/x401.html */
	struct input_event ev;

	if (read(keyboard_fd,&ev,sizeof(struct input_event)) < sizeof(struct input_event)) {
		perror("read");
		return;
	}

	if (EV_KEY != ev.type)
		return;

	if (ev.code >= sizeof(evcodetovk)/sizeof(evcodetovk[0]))
		fprintf(stderr, "Unknown key, ev.code=%d\n", ev.code);
 	// Get key infos
	int pressed = (ev.value != 0);
	int keycode = evcodetovk[ev.code];
	/* Print the keycode. The top bit is the pressed/released flag, and the lower seven are the keycode. */
   	if (keycode!=VK_UNDEFINED)
		printf("%s: %i (%c)\n", pressed ? "Press" : "Release", keycode, keycode);

 	// Handle modifiers (check if we need another keymap)
 	char modifierKeyCode = keycode_map[K_NORMTAB][keycode];
	if (modifierKeyCode == VK_SHIFT) {
		map = pressed ? K_SHIFTTAB : K_NORMTAB;
		printf("shift ==> map=%i\n", map);
	} else if (modifierKeyCode == VK_ALT) {
		map = pressed ? K_ALTTAB : K_NORMTAB;
		printf("alt ==> map=%i\n", map);
	}
}

static bool initializeKeyboard(char *keyboard_device_name) {
	keyboard_fd = open(keyboard_device_name, O_RDONLY, 0);

	if (keyboard_fd < 0) {
		return false;
	}
	
	init_keymap(keyboard_fd);
	
	return true;
}

int main(int argc, char *argv[])
{
	if(initializeKeyboard("/dev/input/event3")==false) exit(1);
	while (1){
		handleKeyEvent();
	}
	return 0;
}
